all repos — caroster @ 535c63f081f0a6a98429277c875b9f475802e4af

[Octree] Group carpool to your event https://caroster.io

frontend/pages/e/[uuid].tsx (view raw)

  1import {useState, useReducer, useEffect} from 'react';
  2import Box from '@material-ui/core/Box';
  3import {makeStyles} from '@material-ui/core/styles';
  4import {useTranslation} from 'react-i18next';
  5import {initializeApollo} from '../../lib/apolloClient';
  6import useToastStore from '../../stores/useToastStore';
  7import useEventStore from '../../stores/useEventStore';
  8import Layout from '../../layouts/Default';
  9import AddToMyEventDialog from '../../containers/AddToMyEventDialog';
 10import TravelColumns from '../../containers/TravelColumns';
 11import NewTravelDialog from '../../containers/NewTravelDialog';
 12import VehicleChoiceDialog from '../../containers/VehicleChoiceDialog';
 13import WelcomeDialog from '../../containers/WelcomeDialog';
 14import EventBar from '../../containers/EventBar';
 15import Loading from '../../containers/Loading';
 16import OnBoardingTour from '../../containers/OnBoardingTour';
 17import {
 18  useUpdateEventMutation,
 19  Event as EventType,
 20  useEventByUuidQuery,
 21  EventByUuidDocument,
 22  EditEventInput,
 23} from '../../generated/graphql';
 24import ErrorPage from '../_error';
 25import AddTravel from '../../containers/TravelColumns/AddTravel';
 26import useProfile from '../../hooks/useProfile';
 27import Fab from '../../containers/Fab';
 28
 29const POLL_INTERVAL = 10000;
 30
 31interface Props {
 32  event: EventType;
 33  eventUUID: string;
 34}
 35
 36const EventPage = props => {
 37  const {t} = useTranslation();
 38  const {event} = props;
 39  if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
 40  return <Event {...props} />;
 41};
 42
 43const Event = (props: Props) => {
 44  const {eventUUID} = props;
 45  const classes = useStyles();
 46  const {t} = useTranslation();
 47  const {user} = useProfile();
 48  const addToast = useToastStore(s => s.addToast);
 49  const setEvent = useEventStore(s => s.setEvent);
 50  const eventUpdate = useEventStore(s => s.event);
 51  const setIsEditing = useEventStore(s => s.setIsEditing);
 52  const [updateEvent] = useUpdateEventMutation();
 53  const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
 54  const [openNewTravel, toggleNewTravel] = useReducer(i => !i, false);
 55  const [openVehicleChoice, toggleVehicleChoice] = useReducer(i => !i, false);
 56  const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
 57    pollInterval: POLL_INTERVAL,
 58    variables: {uuid: eventUUID},
 59  });
 60
 61  useEffect(() => {
 62    if (event) setEvent(event as EventType);
 63  }, [event]);
 64
 65  const onSave = async e => {
 66    try {
 67      const {uuid, ...data} = eventUpdate;
 68      const {id, __typename, travels, users, waitingList, ...input} = data;
 69      await updateEvent({
 70        variables: {uuid, eventUpdate: input as EditEventInput},
 71        refetchQueries: ['eventByUUID'],
 72      });
 73      setIsEditing(false);
 74    } catch (error) {
 75      console.error(error);
 76      addToast(t('event.errors.cant_update'));
 77    }
 78  };
 79
 80  const onShare = async () => {
 81    if (!event) return null;
 82    // If navigator share capability
 83    if (!!navigator.share)
 84      return await navigator.share({
 85        title: `Caroster ${event.name}`,
 86        url: `${window.location.href}`,
 87      });
 88    // Else copy URL in clipboard
 89    else if (!!navigator.clipboard) {
 90      await navigator.clipboard.writeText(window.location.href);
 91      addToast(t('event.actions.copied'));
 92      return true;
 93    }
 94  };
 95
 96  if (!event) return <Loading />;
 97
 98  return (
 99    <Layout
100      pageTitle={t('event.title', {title: event.name})}
101      menuTitle={t('event.title', {title: event.name})}
102      displayMenu={false}
103    >
104      <EventBar
105        event={event}
106        onAdd={setIsAddToMyEvent}
107        onSave={onSave}
108        onShare={onShare}
109      />
110      <TravelColumns toggle={toggleVehicleChoice} />
111      <Box className={classes.bottomRight}>
112        <Fab
113          onClick={(user ? toggleVehicleChoice : toggleNewTravel)}
114          aria-label="add-car"
115          color="primary"
116        >
117          {t('travel.creation.title')}
118        </Fab>
119      </Box>
120      <NewTravelDialog open={openNewTravel} toggle={toggleNewTravel} />
121      <VehicleChoiceDialog
122        open={openVehicleChoice}
123        toggle={toggleVehicleChoice}
124        toggleNewTravel={toggleNewTravel}
125      />
126      <AddToMyEventDialog
127        event={event}
128        open={isAddToMyEvent}
129        onClose={() => setIsAddToMyEvent(false)}
130      />
131      <WelcomeDialog />
132      <OnBoardingTour />
133    </Layout>
134  );
135};
136
137export async function getServerSideProps(ctx) {
138  const {uuid} = ctx.query;
139  const apolloClient = initializeApollo();
140  const {data = {}} = await apolloClient.query({
141    query: EventByUuidDocument,
142    variables: {uuid},
143  });
144  const {eventByUUID: event} = data;
145  const {host = ''} = ctx.req.headers;
146
147  return {
148    props: {
149      event,
150      eventUUID: uuid,
151      metas: {
152        title: event?.name || '',
153        url: `https://${host}${ctx.resolvedUrl}`,
154      },
155    },
156  };
157}
158
159const useStyles = makeStyles(theme => ({
160  bottomRight: {
161    position: 'absolute',
162    bottom: theme.spacing(1),
163    right: theme.spacing(6),
164    width: 200,
165  },
166}));
167
168export default EventPage;